# -*- coding: utf-8 -*-
"""
Module Description:

Date: 2017/3/7
Author:Bai Jin Ping
"""
from common import service_config
from pyshare.framework.firefly_dc.globalobject import GlobalObject
from pyshare.redis_cache.share.scheduler_redis_cache import scheduler_count_data_cache, scheduler_count_cache
from pyshare.utils.time_utils import has_pass_time


def s_get_server_id():
    """获得操作的server id(区服/跨服适配)"""
    if GlobalObject.is_area_server():
        return service_config.get_server_id()
    else:
        return 'cross'


def job_count(job):
    """
    将任务计数 +1
    :param job:
    :return:
    """
    s_job_id = job.get_scheduler_job_id()
    if scheduler_count_data_cache.apply_job(s_job_id) == 1:
        scheduler_count_cache.apply_add()


def job_reduce_count(job):
    """
    任务计数 -1
    :param job:
    :return:
    """
    s_job_id = job.get_scheduler_job_id()
    if scheduler_count_data_cache.delete_job(s_job_id) == 1:
        scheduler_count_cache.apply_reduce()


def job_reduce_count_batch(job_id_list):
    """
    任务计数 -1
    :param job_id_list:
    :return:
    """
    count = scheduler_count_data_cache.delete_jobs(job_id_list)
    if count > 0:
        scheduler_count_cache.apply_reduce(count=count)


def add_cron_job(func, args=None, job_id=None, year=None, month=None, day=None,
                 hour=None, minute=None, second=None,
                 week=None, day_of_week=None,
                 start_date=None, end_date=None, server_id=None):
    """
    添加cron循环任务
    :param func: 执行体
    :param args: 执行参数
    :param job_id: 任务id
    :param start_date: cron开始时间
    :param end_date: cron结束时间
    :param server_id: 'cross' 时表示是应用级的定时任务，不计入区服任务数
    :return Job
    """
    # 增加时间过滤
    if end_date and has_pass_time(end_date):
        return None

    if args is None:
        args = []

    from pyshare.framework.sched.job import Job
    server_id = server_id if server_id else s_get_server_id()
    job = Job(id=job_id, executor=func, args=args,
              server_id=server_id,
              app_id=service_config.get_app_id())
    job_state = job.dump_state()

    # ======= 任务数+1 =======
    job_count(job)

    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.add_cron_job(job_state,
                                  year=year, month=month, day=day,
                                  hour=hour, minute=minute, second=second,
                                  week=week, day_of_week=day_of_week,
                                  start_date=start_date, end_date=end_date)


def add_job(func, args, run_date, job_id, replace_existing=True, server_id=None):
    """
    添加单次定时任务
    :param func: 执行体
    :param args: 任务参数
    :param run_date: 执行时间
    :param job_id: 定时任务id
    :param replace_existing: 若jobId相同，是否替换原有的job
    :param server_id: 'cross' 时表示是应用级的定时任务，不计入区服任务数
    :return Job
    """
    # 增加时间过滤
    if has_pass_time(run_date):
        return None
    if args is None:
        args = []

    from pyshare.framework.sched.job import Job
    server_id = server_id if server_id else s_get_server_id()
    job = Job(id=job_id, executor=func, args=args,
              server_id=server_id,
              app_id=service_config.get_app_id())
    job_state = job.dump_state()

    # ======= 任务数+1 =======
    job_count(job)

    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.add_job(job_state, run_date=run_date,
                             replace_existing=replace_existing)


def add_interval_job(func, args, job_id, weeks=0, days=0, hours=0, minutes=0, seconds=0,
                     start_date=None, end_date=None, max_instances=1, misfire_grace_time=50,
                     replace_existing=True, server_id=None):
    """
    添加间隔任务
    参考 http://debugo.com/apscheduler/
    :param func: 调用方法
    :param args: 方法对应参数tuple,list
    :param job_id: 任务ID
    :param start_date: 开始时间(不论有没有赋值，是否是过去时间，首次触发时间是now + interval)
    :param end_date: 结束时间(若不设置则一直调度)
    :param weeks: 循环间隔，周
    :param days: 循环间隔，天
    :param hours: 循环间隔，小时
    :param minutes: 循环间隔，分钟
    :param seconds: 循环间隔，秒
    :param max_instances: 允许最大并行实例
    :param misfire_grace_time: 丢弃时间，秒
    :param replace_existing: 是否覆盖同id任务
    :param server_id: 'cross' 时表示是应用级的定时任务，不计入区服任务数
    :return Job
    """
    # 增加时间过滤
    if end_date and has_pass_time(end_date):
        return None
    from pyshare.framework.sched.job import Job
    if args is None:
        args = []
    server_id = server_id if server_id else s_get_server_id()
    job = Job(id=job_id, executor=func, args=args,
              server_id=server_id,
              app_id=service_config.get_app_id())
    job_state = job.dump_state()

    # ======= 任务数+1 =======
    job_count(job)

    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.add_interval_job(job_state,
                                      weeks=weeks, days=days,
                                      hours=hours, minutes=minutes, seconds=seconds,
                                      start_date=start_date, end_date=end_date,
                                      max_instances=max_instances, misfire_grace_time=misfire_grace_time,
                                      replace_existing=replace_existing)


def remove_job(func, job_id):
    """
    删除任务
    """

    from pyshare.framework.sched.job import Job
    job = Job(id=job_id, executor=func, args=None,
              server_id=s_get_server_id(),
              app_id=service_config.get_app_id())

    job_state = job.dump_state()

    # ======= 任务数-1 =======
    job_reduce_count(job)

    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.remove_job(job_state)


def get_server_jobs(app_id, server_id):
    """
    获取区服定时任务
    :param app_id:
    :param server_id:
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.get_server_jobs(app_id, server_id)


def get_server_error_jobs(app_id, server_id, start, end):
    """
    获取区服失败定时任务
    :param app_id:
    :param server_id:
    :param start:
    :param end:
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.get_server_error_jobs(app_id, server_id, start, end)


def reload_server_scheduler(app_id, server_id):
    """
    重置区服定时任务
    :param app_id:
    :param server_id:
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.reload_server_scheduler(app_id, server_id)


def get_server_jobs_count(app_id, server_id_list):
    """
    获取区服定时任务
    :param app_id:
    :param server_id_list:
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.get_server_jobs_count(app_id, server_id_list)


def search_jobs(app_id, server_id_list, id_pattern, trigger_type, start_time, end_time):
    """
    条件查询定时任务
    :param app_id: 应用id
    :param server_id_list: 区服id列表
    :param id_pattern: 定时任务id匹配模式
    :param trigger_type: 定时任务运行模式
    :param start_time: 运行开始时间
    :param end_time: 运行结束时间
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.search_jobs(app_id, server_id_list, id_pattern, trigger_type, start_time, end_time)


def remove_jobs_by_batch(job_id_list):
    """
    条件查询定时任务
    :param job_id_list: 应用id
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler

    # 任务计数
    job_reduce_count_batch(job_id_list)
    return scheduler.remove_jobs_by_batch(job_id_list)


def search_job_by_id(app_id, server_id, id_pattern):
    """
    按任务ID查询任务
    按任务ID查询任务
    :param app_id: 大区ID
    :param server_id: 区服ID
    :param id_pattern: 任务ID标识
    :return:
    """
    from pyshare.framework.sched.scheduler.scheduler_adapter import scheduler
    return scheduler.search_job_by_id(app_id, server_id, id_pattern)


def compare_job_diff(app_id, server_id):
    """
    比对任务差异
    :param app_id:
    :param server_id:
    :return:
    """
    # 定时服务的任务数据 {"Jobs": []}
    d = get_server_jobs(app_id, server_id)

    code = d.get('code', -2)
    if code == -2:
        msg = d.get('msg', '')
        raise Exception(msg)
    else:
        job_from_scheduler = d['Jobs']
    # 缓存计数 {}
    job_from_cache = scheduler_count_data_cache.get_all_job_by_server(server_id)

    s_set = set([job['Key'] for job in job_from_scheduler])
    c_set = set(job_from_cache)
    return {'SchedulerLost': list(c_set - s_set), 'CacheLost': list(s_set - c_set)}